package directlinks

import (
	"context"
	"net/http"
	"sync"
	"sync/atomic"

	"github.com/krau/SaveAny-Bot/config"
	"github.com/krau/SaveAny-Bot/pkg/enums/tasktype"
	"github.com/krau/SaveAny-Bot/storage"
)

type File struct {
	Name string
	URL  string
	Size int64
}

func (f *File) FileName() string {
	return f.Name
}

func (f *File) FileSize() int64 {
	return f.Size
}

type Task struct {
	ID       string
	ctx      context.Context
	files    []*File
	Storage  storage.Storage
	StorPath string
	Progress ProgressTracker

	client          *http.Client // [TODO] parallel download
	stream          bool
	totalBytes      int64            // total bytes to download
	downloadedBytes atomic.Int64     // downloaded bytes
	totalFiles      int64            // total files to download
	downloaded      atomic.Int64     // downloaded files count
	processing      map[string]*File // {"url": File}
	processingMu    sync.RWMutex
	failed          map[string]error // [TODO] errors for each file
}

// DownloadedBytes implements TaskInfo.
func (t *Task) DownloadedBytes() int64 {
	return t.downloadedBytes.Load()
}

// Processing implements TaskInfo.
func (t *Task) Processing() []FileInfo {
	t.processingMu.RLock()
	defer t.processingMu.RUnlock()
	infos := make([]FileInfo, 0, len(t.processing))
	for _, f := range t.processing {
		infos = append(infos, f)
	}
	return infos
}

// StorageName implements TaskInfo.
func (t *Task) StorageName() string {
	return t.Storage.Name()
}

// StoragePath implements TaskInfo.
func (t *Task) StoragePath() string {
	return t.StorPath
}

// TotalBytes implements TaskInfo.
func (t *Task) TotalBytes() int64 {
	return t.totalBytes
}

// TotalFiles implements TaskInfo.
func (t *Task) TotalFiles() int {
	return int(t.totalFiles)
}

func (t *Task) Type() tasktype.TaskType {
	return tasktype.TaskTypeDirectlinks
}

func (t *Task) TaskID() string {
	return t.ID
}

func NewTask(
	id string,
	ctx context.Context,
	links []string,
	stor storage.Storage,
	storPath string,
	progressTracker ProgressTracker,
) *Task {
	_, ok := stor.(storage.StorageCannotStream)
	stream := config.C().Stream && !ok
	files := make([]*File, 0, len(links))
	for _, link := range links {
		files = append(files, &File{
			URL: link,
		})
	}
	return &Task{
		ID:           id,
		ctx:          ctx,
		files:        files,
		Storage:      stor,
		StorPath:     storPath,
		Progress:     progressTracker,
		stream:       stream,
		client:       http.DefaultClient,
		processing:   make(map[string]*File),
		processingMu: sync.RWMutex{},
		failed:       make(map[string]error),
		totalFiles:   int64(len(files)),
	}
}
